# -*- coding: utf-8 -*-
"""
xfree.plugins.spec
这个模块提供了 xfree 插件的核心钩子定义。

版权所有 (c) 2017 年由 xfree 团队所有。
许可证为 BSD，更多详情请参见 LICENSE。
"""

from pluggy import HookspecMarker

# 创建一个用于标记 xfree 插件钩子的对象
spec = HookspecMarker("xfree")


# 设置钩子
@spec
def xfree_extensions(app):
    """用于初始化插件加载的扩展。"""


@spec
def xfree_load_translations():
    """用于注册翻译文件夹。"""


@spec
def xfree_load_migrations():
    """用于注册额外的数据库迁移。"""


@spec
def xfree_load_blueprints(app):
    """用于注册蓝图。
    参数 app：应用程序对象。"""


@spec
def xfree_request_processors(app):
    """用于注册请求前/后处理器。
    参数 app：应用程序对象。"""


@spec
def xfree_errorhandlers(app):
    """用于注册错误处理器。
    参数 app：应用程序对象。"""


@spec
def xfree_jinja_directives(app):
    """用于注册 Jinja 过滤器、上下文处理器等。
    参数 app：应用程序对象。"""


@spec
def xfree_additional_setup(app, pluggy):
    """在所有其他应用程序设置完成后，插件想要进行任何额外设置的钩子。
    例如，可以应用一个 WSGI 中间件。
    参数 app：应用程序对象。
    参数 pluggy：Pluggy 对象。"""


@spec
def xfree_load_post_markdown_class(app):
    """用于加载 mistune 渲染器的子类，以便在帖子和用户签名中渲染 Markdown 的钩子。
    这个钩子返回的所有类将组合成一个单独的类，用于渲染帖子的 Markdown。
    由于所有的类将组合在一起，子类应该适当地调用 super，并且不要向 `__init__` 添加任何新的参数，因为这个类将用预先确定的参数实例化。
    参数 app：如果需要，与类相关联的应用程序对象。"""


@spec
def xfree_load_nonpost_markdown_class(app):
    """用于加载 mistune 渲染器的子类，以便在帖子以外的位置渲染 Markdown，例如在类别或论坛描述中。
    这个钩子返回的所有类将组合成一个单独的类，用于渲染非帖子内容的 Markdown，例如论坛和类别描述。
    由于所有的类将组合在一起，子类应该适当地调用 super，并且不要向 `__init__` 添加任何新的参数，因为这个类将用预先确定的参数实例化。
    参数 app：如果需要，与类相关联的应用程序对象。"""


@spec
def xfree_load_post_markdown_plugins(plugins, app):
    """用于加载在帖子和用户签名中渲染 Markdown 时使用的 mistune 渲染器插件的钩子。
    实现应该直接修改 `plugins` 列表。
    参数 plugins：要加载的 mistune 插件列表。
    参数 app：应用程序对象。"""


@spec
def xfree_load_nonpost_markdown_plugins(plugins, app):
    """用于加载在帖子以外的位置渲染 Markdown 时使用的 mistune 渲染器插件的钩子。
    实现应该直接修改 `plugins` 列表。
    参数 plugins：要加载的 mistune 插件列表。
    参数 app：应用程序对象。"""


@spec
def xfree_cli(cli, app):
    """用于注册 CLI 命令的钩子。
    参数 app：应用程序对象。
    参数 cli：xfreeGroup CLI 对象。
    实例：
    @impl
    def xfree_cli(cli):
        @cli.command()
        def testplugin():
            click.echo("Hello Testplugin")

        return testplugin
    """


@spec
def xfree_shell_context():
    """用于注册 shell 上下文处理器的钩子，期望返回一个可调用函数，该函数返回一个字典或键值对的可迭代对象。"""


# 事件钩子
@spec
def xfree_event_post_save_before(post):
    """在帖子保存之前处理帖子的钩子。
    参数 post：触发事件的帖子。"""


@spec
def xfree_event_post_save_after(post, is_new):
    """在帖子保存之后处理帖子的钩子。
    参数 post：触发事件的帖子。
    参数 is_new：如果帖子是新的，则为 True；如果是编辑的，则为 False。"""


@spec
def xfree_event_topic_save_before(topic):
    """在主题保存之前处理主题的钩子。
    参数 topic：触发事件的主题。"""


@spec
def xfree_event_topic_save_after(topic, is_new):
    """在主题保存之后处理主题的钩子。
    参数 topic：触发事件的主题。
    参数 is_new：如果主题是新的，则为 True；如果是编辑的，则为 False。"""


@spec
def xfree_event_user_registered(username):
    """在用户注册后处理事件的钩子（已被弃用，推荐使用 xfree_registration_post_processor）。
    参数 username：新注册用户的用户名。"""


@spec
def xfree_gather_registration_validators():
    """用于收集用户注册验证器的钩子，实现者必须返回一个可调用对象，该对象接受一个 UserRegistrationInfo 类的实例，如果注册无效，则引发 ValidationError 异常，如果注册验证应立即停止，则引发 StopValidation 异常。"""


@spec
def xfree_registration_failure_handler(user_info, failures):
    """用于处理用户注册失败的钩子，接收用户尝试注册的信息以及导致注册失败的错误。"""


@spec
def xfree_registration_post_processor(user):
    """用于在用户成功注册后处理操作的钩子。这个规范在用户对象成功持久化到数据库后接收该对象。"""


@spec(firstresult=True)
def xfree_authenticate(identifier, secret):
    """用于在 xfree 中认证用户的钩子。这个钩子应该返回 User 类的实例或 None。如果一个钩子决定所有的认证尝试都应该结束，它可以引发 StopAuthentication 异常，并包含认证停止的原因。只有第一个用户结果会被使用，并且默认的 xfree 认证是最后尝试的，以便让其他钩子有机会认证用户。"""


@spec
def xfree_post_authenticate(user):
    """用于在用户认证后但在设置为当前用户之前处理操作的钩子。可用于处理多因素认证等情况。如果一个钩子应该需要阻止用户登录，它应该注册为 tryfirst 并引发 StopAuthentication 异常，并包含为什么登录被阻止的原因。结果不被考虑。"""


@spec
def xfree_authentication_failed(identifier):
    """用于处理认证失败事件的钩子。只有当没有认证提供者成功返回用户或在登录过程中引发 StopAuthentication 异常时，这个钩子才会被调用。"""


@spec(firstresult=True)
def xfree_reauth_attempt(user, secret):
    """用于处理重新认证的钩子。这些钩子接收当前已认证的用户和输入的密码。只有第一个响应会被考虑，类似于 authenticate 钩子。成功的尝试应该返回 True，否则对于未尝试或不成功的重新认证返回 None。如果一个钩子决定重新认证尝试应该停止，它可以引发 StopAuthentication。"""


@spec
def xfree_post_reauth(user):
    """在成功重新认证后调用的钩子。用户已经通过了 xfree_reauth_attempt 钩子，但在重新认证被确认之前调用这个钩子，所以一个 post reauth 实现者仍然可以通过引发 StopAuthentication 来强制重新认证失败。结果不被考虑。"""


@spec
def xfree_reauth_failed(user):
    """如果重新认证失败，调用这个钩子。只有当没有实现者为 xfree_reauth_attempt 返回 True 结果，或者一个实现者引发 StopAuthentication 时，这个钩子才会被调用。如果一个实现者引发 ForceLogout，它应该注册为 trylast，以便给其他重新认证失败处理程序一个先运行的机会。"""


# 表单钩子
@spec
def xfree_form_post(form):
    """用于修改帖子回复表单的钩子。
    参数 form：帖子回复表单类。"""


@spec
def xfree_form_post_save(form, post):
    """在填充帖子对象时调用，用于修改帖子回复表单。
    参数 form：表单对象。
    参数 post：帖子对象。"""


@spec
def xfree_form_topic(form):
    """用于修改新主题表单的钩子。
    参数 form：新主题表单类。"""


@spec
def xfree_form_topic_save(form, topic):
    """在填充主题对象时调用，用于修改新主题表单。
    参数 form：表单对象。
    参数 topic：主题对象。"""


@spec
def xfree_form_registration(form):
    """用于修改注册表单的钩子。
    参数 form：注册表单类。"""


@spec
def xfree_gather_password_validators(app):
    """用于收集专门处理密码更新的 ChangeSetValidator 实例的钩子。应该返回一个可迭代对象。
    参数 app：当前应用程序。"""


@spec
def xfree_gather_email_validators(app):
    """用于收集专门处理邮箱更新的 ChangeSetValidator 实例的钩子。应该返回一个可迭代对象。
    参数 app：当前应用程序。"""


@spec
def xfree_gather_details_update_validators(app):
    """用于收集专门处理用户详细信息更新的 ChangeSetValidator 实例的钩子。应该返回一个可迭代对象。
    参数 app：当前应用程序。"""


@spec
def xfree_details_updated(user, details_update):
    """在用户更新详细信息后调用的钩子。
    参数 user：用户对象。
    参数 details_update：应用到用户的详细信息更改集。"""


@spec
def xfree_password_updated(user):
    """在用户更新密码后调用的钩子。
    参数 user：更新密码的用户对象。"""


@spec
def xfree_email_updated(user, email_update):
    """在用户更新邮箱后调用的钩子。
    参数 user：用户对象。
    参数 email_update：应用到用户的邮箱更改集。"""


@spec
def xfree_settings_updated(user, settings_update):
    """在用户更新设置后调用的钩子。
    参数 user：用户对象。
    参数 settings_update：应用到用户的设置更改集。"""


# 模板钩子
@spec
def xfree_tpl_navigation_before():
    """用于在模板的导航部分添加内容的钩子，在导航栏之前添加。"""


@spec
def xfree_tpl_navigation_after():
    """用于在模板的导航部分添加内容的钩子，在导航栏之后添加。"""


@spec
def xfree_tpl_user_nav_loggedin_before():
    """用于在用户登录后添加导航项的钩子，在用户导航栏之前添加。"""


@spec
def xfree_tpl_user_nav_loggedin_after():
    """用于在用户登录后添加导航项的钩子，在用户导航栏之后添加。"""


@spec
def xfree_tpl_form_registration_before(form):
    """在注册表单中，在第一个输入字段之前添加内容的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_form_registration_after(form):
    """在注册表单中，在最后一个输入字段之后添加内容的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_form_user_details_before(form):
    """在用户详细信息更改表单中，在每个输入字段之前添加内容的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_form_user_details_after(form):
    """在用户详细信息更改表单中，在最后一个输入字段之后添加内容的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_profile_settings_menu(user):
    """在用户设置页面上，用于填充侧边栏菜单的钩子。实现应该返回一个包含视图名称和显示文本的元组列表。显示文本将被提供给翻译服务，因此不需要提供翻译后的文本。如果一个插件声明一个新的块，可以将视图设置为 None。考虑将钩子实现标记为 trylast=True，以避免捕获不创建新块的插件。
    参数 user：设置菜单正在为其渲染的用户对象。"""


@spec
def xfree_tpl_profile_sidebar_links(user):
    """在用户资料页面上，用于填充侧边栏菜单的钩子。实现应该返回一个 NavigationItem 实例的可迭代对象。
    参数 user：用户资料页面所属的用户对象。"""


@spec
def xfree_tpl_admin_settings_menu(user):
    """在管理面板中，用于添加额外导航链接到管理菜单的钩子。实现应该返回一个包含视图名称、显示文本和可选图标的元组列表。显示文本将被提供给翻译服务，因此不需要提供翻译后的文本。如果要添加的项仅在用户是管理员时显示，可以检查当前用户是否是管理员。
    参数 user：当前用户对象。"""


@spec
def xfree_tpl_admin_settings_sidebar(user):
    """在管理面板的设置选项卡中，用于添加额外导航链接到侧边栏设置菜单的钩子。实现应该返回一个包含视图名称和显示文本的元组列表。显示文本将被提供给翻译服务，因此不需要提供翻译后的文本。只有管理员可以查看设置选项卡。
    参数 user：当前用户对象。"""


@spec
def xfree_tpl_profile_sidebar_stats(user):
    """在用户资料页面上，用于在标准信息下方添加内容的钩子。例如，可以用于添加其他项目，如链接到个人资料。
    参数 user：正在访问其资料的用户对象。"""


@spec
def xfree_tpl_post_author_info_before(user, post):
    """在帖子中，在显示作者信息之前添加内容的钩子。
    参数 user：帖子作者的用户对象。
    参数 post：帖子对象。"""


@spec
def xfree_tpl_post_author_info_after(user, post):
    """在帖子中，在显示作者信息之后添加内容的钩子。
    参数 user：帖子作者的用户对象。
    参数 post：帖子对象。"""


@spec
def xfree_tpl_post_content_before(post):
    """在帖子内容渲染之前进行处理的钩子。
    参数 post：当前帖子对象。"""


@spec
def xfree_tpl_post_content_after(post):
    """在帖子内容渲染之后进行处理的钩子。
    参数 post：当前帖子对象。"""


@spec
def xfree_tpl_post_menu_before(post):
    """在帖子菜单的开头插入新项的钩子。
    参数 post：当前帖子对象。"""


@spec
def xfree_tpl_post_menu_after(post):
    """在帖子菜单的末尾插入新项的钩子。
    参数 post：当前帖子对象。"""


@spec
def xfree_tpl_topic_controls(topic):
    """在主题控制模板中插入额外主题审核控制的钩子。
    参数 topic：当前主题对象。"""


@spec
def xfree_tpl_form_new_post_before(form):
    """在新帖子表单中，在第一个字段渲染之前插入新表单字段的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_form_new_post_after(form):
    """在新帖子表单中，在最后一个字段渲染之后（但在提交按钮之前）插入新表单字段的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_form_new_topic_before(form):
    """在新主题表单中，在第一个字段渲染之前（但在 CSRF 令牌之后）插入新表单字段的钩子。
    参数 form：表单对象。"""


@spec
def xfree_tpl_form_new_topic_after(form):
    """在新主题表单中，在最后一个字段渲染之后（但在提交按钮之前）插入新表单字段的钩子。
    参数 form：表单对象。"""